# Module.py        
"""
Author :: Albert Rondan
Description :: in conjunction with clingo's output AND input, this file assigns weights to each generated schedule according
to the number of consecutive home games and the number of games a club has over its maximum
smaller the weight, the better fit the schedule
"""
import sys
import math

NUMBER_SCHEDULES = 0
scheduleList = []                     
weightDict = {}            
clubTeam = {}             
clubMax = {}               
clubCount = {}
instList = {}
# weightDict = {weight : schedule}
# clubTeam = {team : club}
# clubMax = {club : [max]}
# clubCount = {club : [count]}
# instList = {(pair) : [instance]}

NUM_RESULTS_TO_PRINT = 1

def main( given, fileName ) :
    weightDict = {}
    #given is the string composed of the entirety of clingo's output for a particular scheduling problem
   # input = sys.stdin
    input = given
    #print "from Module.py"
    #print input
    loadClubTeam(fileName)                                                                
    for i, x in enumerate(input):
        if x.find("res") != -1 :
            #print x                           
            curSchedule = x                                 
            resList = x.rsplit(" ")                         # get rid of the /n character from the list (byproduct of input)
            resList = resList[0:len(resList)-1]             # resList now has the list of "res" elements to analyze and assign weight
            curWeight = assignWeight(resList)
            #append to weightDict. how to deal with duplicates?
            if curWeight != -1 :
                weightDict[curWeight] = resList
            while len(weightDict) > NUM_RESULTS_TO_PRINT:
                del weightDict[max(weightDict.keys())]
        if i % 10000 == 0:
            print i
    i=0
    final = ""
    for key in sorted(weightDict.iterkeys()) :               # loop throug dictionary in order of key values. first printed result is the best fit.
        print "SCHEDULE :: " + str(i)
        i+=1        
        print "WEIGHT ::"+ str(key)
        #print weightDict[key]
        
        for result in weightDict[key]:
            print result
            final += result+" "
        print ""
    return final

def loadClubTeam(fileName) :
    stream = open(fileName,"r")                                  # change to match name of clingo input file
    cur = stream.readline()
    done = False
    
    while cur != '' :	
        if cur.find("home") != -1 and cur.find("%") == -1 :
            team = cur[cur.find("(")+1:cur.find(",")]
            club = cur[cur.find(",")+1:cur.find(")")]
            clubTeam[team] = club
        elif cur.find("inst") != -1 and cur.find("%") == -1 :		
            team = cur[cur.find("(")+1:cur.find(",")]
            cur = cur[cur.find(",")+1:]
            instanceNum = cur[0:cur.find(",")]
            cur = cur[cur.find(",")+1:cur.find(")")]
            instList[(team,instanceNum)] = cur
        elif cur.find("max") != -1 and cur.find("%") == -1:
            maxAssign = cur[cur.find("(")+1:cur.find(")")]
            club = maxAssign[0:maxAssign.find(",")]
            rest = maxAssign[maxAssign.find(",")+1:]		    # week, time, day, max number

            if club not in clubMax :
                clubMax[club] = []	#once club is extracted, we store the remaining 4 numbers in the list
            clubMax[club].append(rest)

            done = True
        elif done :
	        break               # we have everything we need
            
        cur = stream.readline()
    stream.close()

def assignWeight( resultList ) : 
    weight = 0
    #weight1 = 0
    #weight2 = 0
    #weight3 = 0

    clubCount = {}              # clear list weight = 0 #print resultList[0]
   
    resultList = [tuple(x[4:-1].split(",")) for x in resultList]        #due to "rest" being the predicate for the double round robin, resultList 
                                                                        #needs to go to index 5 first How do I have it detect shit? I KNOW!
    resultList = [(a,b,c,int(d)) for a,b,c,d in resultList]

    by_home = {}
    home_count = {}
    away_count = {}		
    for cur in resultList :
        home = cur[0]
        inst = cur[1]
        away = cur[2]
        week = cur[3]
        club = clubTeam[home]
        #maxList = clubMax[club]
        instDate = instList[(home,inst)].split(",")
        #checking for schedules that have games exceeding the max limit at a certain max() fact.
        if club in clubMax:
            for i in range(len(clubMax[club])):
                temp = clubMax[club][i].split(",")
                mWeek = temp[0]
                mTime = temp[1]
                mDay = temp[2]
                maximum = int(temp[3])
                if int(week) == int(mWeek) and int(instDate[0]) == int(mTime) and instDate[1] == mDay:
                    if club not in clubCount:
                        clubCount[club] = [0 for x in range(len(clubMax[club]))]
                    clubCount[club][i] += 1
                    if clubCount[club][i] > maximum:		#for every game that pushes the club past its limit, assign a HEAVY weight
                        weight+= math.pow(5,clubCount[club][i]-maximum)
                        #weight1 += math.pow(5,clubCount[club][i]-maximum)
                        #print "max club game allotment weight :: ",weight1
                        #print "MAX GAMES EXCEEDED :: CLUB="+club+" MAX="+str(maximum)+" CURRENT="+str(clubCount[club][i])
                        #alternatively, if you just want to discard any schedules that exceed a clubs max, just set the weight to a really big number
        if home not in by_home:
            by_home[home] = []
        if home not in home_count:	
            home_count[home] = 0
        if away not in away_count:
            away_count[away] = 0
        #just incase there are teams that dont play home
        if home not in away_count:
            away_count[home] = 0
		
        by_home[home].append(cur)
        home_count[home] = home_count[home]+1
        away_count[away] = away_count[away]+1
        #use this to count the number of home games each team has
	
    from itertools import izip			
    for hometeam, results in by_home.iteritems():
        #since we are going to iterate once through each team, we can use hometeam to check home and away counts for every team
        hCount = home_count[hometeam]
        aCount = away_count[hometeam]
        if hCount > aCount: #imbalanace of home/away games check
            weight+= math.pow(1.25,hCount-aCount)				#this is a heavy weight
            #weight2+= math.pow(1.25,hCount-aCount)				#this is a heavy weight
            #print "home away count weight :: ", weight2
            #print "IMBALANCE DETECTED ::" + hometeam + " H:"+str(hCount) + " A:"+str(aCount)
        results = sorted(results, key=lambda x:x[3])
        count = 0
        for cur, next in izip(results, results[1:]):    #consecutive home/away matchness
            if cur[3]+1 == next[3]:
                #weight += 5
                count+=1
        weight+=math.pow(1.25,count)
        #weight3+=math.pow(1.25,count)
        #print "Consecutive game weight added: ", weight3
    #print "game got a total weight of:", weight, "weights: ", (weight1, weight2, weight3)
    #print "-" * 30
    #print
    #print
    return weight
    
    
#main()
